package com.adamfass.tractorbeam.gameupdatelogic;

import java.util.List;

import com.adamfass.tractorbeam.PhysicsGameObject;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.shape.Cylinder;

public class TractorBeamTargeter {
  private final Node rootNode;
  private final List<PhysicsGameObject> targetList;
  private final PhysicsGameObject shooter;
  private final Node feedbackGeometry;
  
  private PhysicsGameObject target;
  private boolean feedbackGeometryAttached = false;
  private boolean feedbackVisible = false;
  private boolean targetInRangeForFeedback = false;
  
  public TractorBeamTargeter(Node rootNode, PhysicsGameObject shooter, 
      List<PhysicsGameObject> targetList) {
    this.rootNode = rootNode;
    this.shooter = shooter;
    this.targetList = targetList;
    
    feedbackGeometry = new Node();
    addCylindersToNode(feedbackGeometry, 20);
  }
  
  private static void addCylindersToNode(Node node, int count) {
    final float height = 1f / ((2 * count) - 1); 
    for (int i = 0; i < count; i++) {
      final Cylinder cylinder = new Cylinder("feedback", 2, 6, 1, height, false);
      cylinder.setLocalTranslation(
          new Vector3f(0, 0, -0.5f + (height * ((i * 2) + 0.5f))));
      cylinder.updateGeometricState(0, true);
      node.attachChild(cylinder);
    }
  }
  
  public final void update() {
    float distanceSquaredToClosestTarget = Float.MAX_VALUE;
    target = null;
    for (PhysicsGameObject potentialTarget : targetList) {
      if (potentialTarget == shooter) {
        continue;
      }
      final float distanceSquared = 
        potentialTarget.getPosition().distanceSquared(
            shooter.getPosition());
      if (distanceSquared < distanceSquaredToClosestTarget) {
        distanceSquaredToClosestTarget = distanceSquared;
        target = potentialTarget;
      }
    }
    
    final Vector3f shooterToTarget = target.getPosition().subtract(
        shooter.getPosition());
    
    feedbackGeometry.setLocalScale(new Vector3f(1, 1, shooterToTarget.length()));
    
    final Matrix3f rotation = new Matrix3f();
    rotation.fromStartEndVectors(Vector3f.UNIT_Z, shooterToTarget.normalize());
    feedbackGeometry.setLocalRotation(rotation);
    
    final Vector3f translation = new Vector3f();
    translation.interpolate(
        shooter.getPosition(), target.getPosition(), 0.5f);
    feedbackGeometry.setLocalTranslation(translation);
    
    feedbackGeometry.updateGeometricState(0, true);
    
    targetInRangeForFeedback = 
      FastMath.sqrt(distanceSquaredToClosestTarget) 
      <= TractorBeamGameUpdateLogic.END_DISTANCE;
      
    updateAttached();
  }
  
  public void showTargetingFeedback() {
    feedbackVisible = true;
    updateAttached();
  }
  
  public void hideTargetingFeedback() {
    feedbackVisible = false;
    updateAttached();
  }
  
  private void updateAttached() {
    final boolean newAttached = feedbackVisible && targetInRangeForFeedback;
    if (newAttached != feedbackGeometryAttached) {
      feedbackGeometryAttached = newAttached;
      if (feedbackGeometryAttached) {
        rootNode.attachChild(feedbackGeometry);
      } else {
        feedbackGeometry.removeFromParent();
      }
    }
  }
  
  public final PhysicsGameObject getTarget() {
    return target;
  }
}
